En este trabajo se replicarán gráficos útiles para visualizar y resumir variables categóricas.

Las librerías necesarias son:

library(vcd)
library(dplyr)
library(plotly)
library(janitor)
library(ggplot2)
library(ggalluvial)
library(ggcleveland)
library(treemapify)
library(tidyverse)
library(plotly)
library(lattice)
knitr::opts_chunk$set(echo = TRUE)

Se fija un tema para los gráficos:

theme_set(theme_bw())

ANALISIS DESCRIPTIVO

Se utilizarán los datos de fútbol del paquete ggcleveland, con datos sobre la distancia (dist) que recorre la pelota al ser pateada según la longitud de pierna (longp) del jugador. Estos datos pueden considerarse univariados, ya que son mediciones de una única variable cuantitativa (la distancia). La longitud de pierna es una variable categórica que clasifica a los jugadores en distintos grupos. El objetivo es determinar si la distancia está relacionada con la longitud de pierna. Se podría esperar que los jugadores de piernas más largas tengan una contextura física mayor y por lo tanto posean mayor potencia al patear.

Resumen y visualización de los datos:

summary(futbol)
##     longp                dist       
##  Length:300         Min.   : 30.00  
##  Class :character   1st Qu.: 60.00  
##  Mode  :character   Median : 71.00  
##                     Mean   : 70.07  
##                     3rd Qu.: 81.00  
##                     Max.   :114.00
futbol

GRÁFICO DE BARRAS

tabla_frec <- count(futbol, longp, name = "Frecuencia")
tabla_frec
tabla_frec=mutate(tabla_frec, 
                  porcentaje_etiqueta=str_c(as.character(round(tabla_frec$Frecuencia/sum(tabla_frec$Frecuencia)*100)),"%"),
                  porcentaje=tabla_frec$Frecuencia/sum(tabla_frec$Frecuencia)*100,
                  longp=factor(longp, levels=c("1.21 m y +",
                                              "1.11 a 1.20 m",
                                              "1.01 a 1.10 m",
                                              "0.91 a 1.00 m",
                                              "0.81 a 0.90 m",
                                              "< 0.81 m"))
                  )
ggplot(data = tabla_frec) +
  coord_flip()+
  aes(x = longp, y = porcentaje, fill=porcentaje) +
  geom_bar(stat = "identity") +
  scale_fill_continuous(low = "lightblue", high = "blue") +
  geom_label(
    aes(label = porcentaje_etiqueta), 
    vjust = 0.5, size = 5,hjust=1,
    color = "black",
    position = "identity"
  ) +
  scale_y_continuous(breaks = seq(0, 60, 10)) +
  labs(x = "Longitud de pierna", y = "Porcentaje")+
  theme(legend.position = "none")

Este gráfico tiene orientación horizontal, el color de cada barra está asociado a su magnitud y el eje X representa los porcentajes de cada categoría de longitud de pierna. Se observa que la categoría de longitud de pierna más popular es “<0.81 m” con aproximadamente un 19%, seguida por “1.11 a 1.20 m” con aproximadamente un 17%.

MOSAICOS

Se toma la variable dist de los datos futbol y se convierte en un factor con dos niveles: “distancia recorrida menor a 50 mts.” y “distancia mayor o igual a 50 mts.”.

A partir de ello se realizan gráficos de mosaico, con test de independencia incluido, para comparar grupos de longitudes de pierna sucesivos (comparaciones de a 2).

1er vs 2do grupo

futbol2=filter(futbol,(longp=="< 0.81 m")|(longp=="0.81 a 0.90 m"))
futbol2=mutate(futbol2,
               dist2=ifelse(futbol2$dist<50,"[30;50)","[50;115)")
               )
mosaic( ~ longp + dist2, data = futbol2, direction = "v", shade = TRUE)

Se observa que los jugadores con una longitud de pierna “< 0.81 m” patean una distancia entre [50;115) en menor proporción que los que tienen una longitud de pierna de “0.81 a 0.90 m” pero es al revés para una distancia entre “[30;50)”

\(H_0)\) La longitud de pierna y la distancia son independientes

\(H_1)\) La longitud de pierna y la distancia no son independientes

En base a la evidencia muestral y con un nivel de significación del 5% se concluye que se rechaza la hipótesis nula de independencia entre la longitud de pierna y la distancia ya que se observa un valor de probabilidad asociado menor a 0.05. Estas variables se distribuyen de diferente forma para los distintos niveles de la otra.

2er vs 3er grupo

futbol3=filter(futbol,(longp=="0.81 a 0.90 m")|(longp=="0.91 a 1.00 m"))
futbol3=mutate(futbol3,
               dist3=ifelse(futbol3$dist<50,"[30;50)","[50;115)")
)
mosaic( ~ longp + dist3, data = futbol3, direction = "v", shade = TRUE)

Se observa que los jugadores con una longitud de pierna “0.81 a 0.90 m” patean una distancia entre [50;115) en menor proporción que los que tienen una longitud de pierna de “0.91 a 1.00 m” pero es al revés para una distancia entre “[30;50)”.

\(H_0)\) La longitud de pierna y la distancia son independientes

\(H_1)\) La longitud de pierna y la distancia no son independientes

En base a la evidencia muestral y con un nivel de significación del 5% se concluye que se rechaza la hipótesis nula de independencia entre la longitud de pierna y la distancia ya que se observa un valor de probabilidad asociado menor a 0.05. Estas variables se distribuyen de diferente forma para los distintos niveles de la otra.

3er vs 4to grupo

futbol4=filter(futbol,(longp=="0.91 a 1.00 m")|(longp=="1.01 a 1.10 m"))
futbol4=mutate(futbol4,
               dist4=ifelse(futbol4$dist<50,"[30;50)","[50;115)")
)
mosaic( ~ longp + dist4, data = futbol4, direction = "v", shade = TRUE)

Se observa que los jugadores con una longitud de pierna “0.91 a 1.00 m” patean una distancia entre [50;115) en proporción muy similar que los que tienen una longitud de pierna de “1.01 a 1.10 m” y se observa lo mismo para una distancia entre “[30;50)”.

\(H_0)\) La longitud de pierna y la distancia son independientes

\(H_1)\) La longitud de pierna y la distancia no son independientes

En base a la evidencia muestral y con un nivel de significación del 5% se concluye que no se rechaza la hipótesis nula de independencia entre la longitud de pierna y la distancia ya que se observa un valor de probabilidad asociado mayor a 0.05. Debe tenerse en cuenta el cumplimiento de los supuestos del test de independencia.

4to vs 5to grupo

futbol5=filter(futbol,(longp=="1.01 a 1.10 m")|(longp=="1.11 a 1.20 m"))
futbol5=mutate(futbol5,
               dist5=ifelse(futbol5$dist<50,"[30;50)","[50;115)")
)
mosaic( ~ longp + dist5, data = futbol5, direction = "v", shade = TRUE)

Se observa que los jugadores con una longitud de pierna “1.01 a 1.10 m” patean una distancia entre [50;115) proporción similar a los que tienen una longitud de pierna de “1.11 a 1.20 m” pero parece ser levemente mayor la cantidad de jugadores con longitud de pierna “1.01 a 1.10 m” que patean una distancia entre “[30;50)”.

\(H_0)\) La longitud de pierna y la distancia son independientes

\(H_1)\) La longitud de pierna y la distancia no son independientes

En base a la evidencia muestral y con un nivel de significación del 5% se concluye que no se rechaza la hipótesis nula de independencia entre la longitud de pierna y la distancia ya que se observa un valor de probabilidad asociado mayor a 0.05. Debe tenerse en cuenta el cumplimiento de los supuestos del test de independencia.

5to vs 6to grupo

futbol6=filter(futbol,(longp=="1.11 a 1.20 m")|(longp=="1.21 m y +"))
futbol6=mutate(futbol6,
               dist6=ifelse(futbol6$dist<50,"[30;50)","[50;115)")
)
mosaic( ~ longp + dist6, data = futbol6, direction = "v", shade = TRUE)
## Warning in legend(residuals, gpfun, residuals_type): All residuals are zero.

Se observa que todos los jugadores con longitud de pierna “1.11 a 1.20 m” y “1.21 m y +” patean la pelota a una distancia entre 50 y 115 m.

\(H_0)\) La longitud de pierna y la distancia son independientes

\(H_1)\) La longitud de pierna y la distancia no son independientes

En base a la evidencia muestral y con un nivel de significación del 5% se concluye que no se rechaza la hipótesis nula de independencia entre la longitud de pierna y la distancia ya que se observa un valor de probabilidad asociado mayor a 0.05. Debe tenerse en cuenta el cumplimiento de los supuestos del test de independencia.

ALLUVIAL

Para este gráfico se utilizan datos sobre toneladas producidas en Argentina de varios tipos de cultivos (soja, trigo, cebada, etc.) desagregados a nivel provincial y departamental para la campaña agrícola 2019/20.

A partir de estos se genera un gráfico alluvial para comparar las producciones de sorgo y girasol en las provincias de Santa Fe, Córdoba y La Pampa.

Resumen y visualización de los datos:

load("C:/Users/Temp/Documents/1 Facultad/Tercero/TAE/TP 4/cultivos.RData")
summary(cultivos)
##      prov              depto             cultivo               prod        
##  Length:1951        Length:1951        Length:1951        Min.   :     25  
##  Class :character   Class :character   Class :character   1st Qu.:   1500  
##  Mode  :character   Mode  :character   Mode  :character   Median :   8100  
##                                                           Mean   :  73026  
##                                                           3rd Qu.:  50075  
##                                                           Max.   :2915400
cultivos
cultivos2 <- cultivos %>% 
     filter(prov=="CORDOBA"|prov=="LA PAMPA"|prov=="SANTA FE") %>%
     filter(cultivo=="Girasol"|cultivo=="Sorgo") %>%
     group_by(prov,cultivo) %>% 
     summarise(prod = sum(prod))
cultivos2=mutate(cultivos2,"Tn. (100.000)"=prod/100000)
cultivos2 %>% 
  #as.data.frame() %>% 
  ggplot() + 
  aes(axis1 = prov, axis2 = cultivo, fill = `Tn. (100.000)`, y = prod) +
  geom_alluvium() + #flujos
  geom_stratum( #columnas
    fill = "black", 
    color = "lightgrey",
    width = 0.1
  ) + 
  geom_label( #etiquetas
    stat = "stratum", 
    aes(label = after_stat(stratum)),
    fill = "white",
    size = 2
  ) + 
  scale_x_discrete(limits = c("Provincia", "Cultivo"), expand = c(0, 0)) +
  scale_y_continuous(name = "Produccion en (100.000 Tn.)", breaks = seq(0, 1500000, 500000), labels =seq(0, 15, 5) )+
  scale_fill_continuous(low = "yellow", high = "red")

A partir de este gráfico se observa que Santa Fe es la provincia que tiene mayor producción de Sorgo y de Girasol, y que esta es similar para ambos cultivos. Mientras que Córdoba y La Pampa producen cantidades diferentes de Sorgo y Girasol (Córdoba produce mayor cantidad de Sorgo y La Pampa produce mayor cantidad de Girasol).

TREEMAPS

Para este gráfico se utiliza el conjunto de datos Titanic del paquete de R Base datasets que contiene el porcentaje de pasajeros/as que sobrevivieron a la tragedia del barco, desagregados según edad, género y clase en la que viajaban.

Resumen y visualización de los datos:

A partir de estos datos se replica un treemap dinámico que muestra los porcentajes de supervivencia según la clase en la que viajaba cada pasajero:

titanic=as.data.frame(Titanic)
titanic=mutate(titanic,Survived=ifelse(Survived=="No","No Sobrevivió","Sobrevivió"))

titanic2 <- titanic %>% 
  group_by(Class, Survived) %>% 
  summarise(Freq = sum(Freq)) %>% 
  ungroup()
## `summarise()` has grouped output by 'Class'. You can override using the
## `.groups` argument.
titanic_tot <- titanic2 %>% 
  group_by(Class) %>% 
  summarise(Freq = sum(Freq))%>%
  ungroup() %>% 
  rename(Survived = Class) %>% 
  mutate(Class = "Total Titanic") %>%
  bind_rows(titanic2)%>%
  mutate(etiq = ifelse(Class != "Total Titanic",
                       paste0(Survived, "_", Class),
                       as.character(Survived)))
plot_ly(
  type = "treemap",
  labels = titanic_tot$etiq, #variable de menor jerarquía (etiqueta única)
  parents = titanic_tot$Class, #variable de mayor jerarquía
  values = titanic_tot$Freq, #tamaño de cada rectángulo
  hoverinfo = "label+value+percent parent+percent root",
  textinfo = "label+value+percent parent+percent root"
)%>%
  add_trace(branchvalues = "total", name = "")

A partir de este gráfico se observa que de la tripulación no sobrevivieron 673 pasajeros que representan el 31% del total de los pasajeros del Titanic y el 76% de la tripulación. Mientras que, sobrevivieron 212 pasajeros de la tripulación. De los pasajeros que viajaron en primera clase sobrevivió el 62% (203 pasajeros), que representa el 9% del total de pasajeros. Siendo mayor el porcentaje de pasajeros que sobrevivieron.
Para la segunda y tercera clase, fue mayor el porcentaje de pasajeros que no sobrevivieron, al igual que para la tripulación.

MAPAS

La georreferencia es una disciplina ligada al análisis de datos recolectados a nivel geográfico. Esta característica implica que la información que poseemos puede visualizarse de manera más eficiente desde una perspectiva espacial, es decir, representando los datos en mapas y no mediante gráficos, tablas u otros instrumentos. En esta parte del trabajo se realizarán esta clase de mapas.

Las librerías a utilizar son:

#Mapas
library(sf)
library(tmap)
library(leaflet)
library(spData)
#Varios
library(dplyr)
library(tidyr)
library(readxl)
library(ggplot2)
library(stringr)

Para realizar estos gráficos se utiliza el conjunto de datos world del paquete spData. Cada una de las 177 filas de esta base corresponde a un país diferente, para los cuales se registran diversas variables: nombre, continente, superficie, población, etc.

Resumen y visualización de los datos:

summary(world)
##     iso_a2           name_long          continent          region_un        
##  Length:177         Length:177         Length:177         Length:177        
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##   subregion             type              area_km2             pop           
##  Length:177         Length:177         Min.   :    2417   Min.   :5.630e+04  
##  Class :character   Class :character   1st Qu.:   46185   1st Qu.:3.755e+06  
##  Mode  :character   Mode  :character   Median :  185004   Median :1.040e+07  
##                                        Mean   :  832558   Mean   :4.282e+07  
##                                        3rd Qu.:  621860   3rd Qu.:3.075e+07  
##                                        Max.   :17018507   Max.   :1.364e+09  
##                                                           NA's   :10         
##     lifeExp        gdpPercap                   geom    
##  Min.   :50.62   Min.   :   597.1   MULTIPOLYGON :177  
##  1st Qu.:64.96   1st Qu.:  3752.4   epsg:4326    :  0  
##  Median :72.87   Median : 10734.1   +proj=long...:  0  
##  Mean   :70.85   Mean   : 17106.0                      
##  3rd Qu.:76.78   3rd Qu.: 24232.7                      
##  Max.   :83.59   Max.   :120860.1                      
##  NA's   :10      NA's   :17
world

Paquete SF

Usando funciones del paquete sf, se grafican los países de América del Sur asignando colores de acuerdo a su esperanza de vida.

data(world)
sudamerica= world %>% filter(continent == "South America")
ggplot(data = sudamerica) +
  aes(fill = lifeExp) +
  ggtitle("Esperanza de Vida (en Años) por País - Datos 2014")+
  geom_sf() +
  scale_fill_gradient(low = "red", high = "green") +
  theme_bw()

A partir de este mapa se observa que Chile es el país con mayor esperanza de vida entre los países de América del Sur, seguido por Uruguay y Argentina. Mientras que, Guayana y Bolivia son los países con menor esperanza de vida.

Paquete TMAP

Se realiza un mapa usando funciones del paquete tmap, donde se comparan los valores de PBI per cápita de los países africanos:

tmap_mode("plot")
## tmap mode set to plotting
africa= world %>% filter(continent == "Africa")

africa %>% 
  tm_shape() + 
  tm_fill(id = "name_long", col = "gdpPercap") +
  tm_style("cobalt") +
  tm_borders("black", lwd = 1) + 
  tm_minimap() +
  tm_basemap("Stamen.TonerBackground")+
  tm_text( "name_long", size=.6)

A partir de este mapa se observa que los países con mayor PBI per cápita en África son Guinea Ecuatorial, Libia y Botswana. Mientras que los de menor PBI per cápita son, entre otros; Nigeria, Sudán, Madagascar, etc. Hay mayor proporción de países con PBI per cápita bajo.

LS0tDQp0aXRsZTogIkFuYWxpc2lzIEV4cGxvcmF0aW9yaW8gZGUgRGF0b3MiDQphdXRob3I6ICJSb23DoW4gTGFuZGEiDQpkYXRlOiAiMjAyMi0xMS0yMyINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IHVuaXRlZA0KICAgIGRmX3ByaW50OiBwYWdlZA0KbGluay1jaXRhdGlvbnM6IHllcw0KLS0tDQpFbiBlc3RlIHRyYWJham8gc2UgcmVwbGljYXLDoW4gZ3LDoWZpY29zIMO6dGlsZXMgcGFyYSB2aXN1YWxpemFyIHkgcmVzdW1pciB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzLg0KDQpMYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzIHNvbjoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQ0KbGlicmFyeSh2Y2QpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGphbml0b3IpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdnYWxsdXZpYWwpDQpsaWJyYXJ5KGdnY2xldmVsYW5kKQ0KbGlicmFyeSh0cmVlbWFwaWZ5KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkobGF0dGljZSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQpTZSBmaWphIHVuIHRlbWEgcGFyYSBsb3MgZ3LDoWZpY29zOg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCnRoZW1lX3NldCh0aGVtZV9idygpKQ0KYGBgDQoNCiMgQU5BTElTSVMgREVTQ1JJUFRJVk8NCg0KU2UgdXRpbGl6YXLDoW4gbG9zIGRhdG9zIGRlIGbDunRib2wgZGVsIHBhcXVldGUgKmdnY2xldmVsYW5kKiwgY29uIGRhdG9zIHNvYnJlIGxhIGRpc3RhbmNpYSAoZGlzdCkgcXVlIHJlY29ycmUgbGEgcGVsb3RhIGFsIHNlciBwYXRlYWRhIHNlZ8O6biBsYSBsb25naXR1ZCBkZSBwaWVybmEgKGxvbmdwKSBkZWwganVnYWRvci4NCkVzdG9zIGRhdG9zIHB1ZWRlbiBjb25zaWRlcmFyc2UgdW5pdmFyaWFkb3MsIHlhIHF1ZSBzb24gbWVkaWNpb25lcyBkZSB1bmEgw7puaWNhIHZhcmlhYmxlIGN1YW50aXRhdGl2YSAobGEgZGlzdGFuY2lhKS4gTGEgbG9uZ2l0dWQgZGUgcGllcm5hIGVzIHVuYSB2YXJpYWJsZSBjYXRlZ8OzcmljYSBxdWUgY2xhc2lmaWNhIGEgbG9zIGp1Z2Fkb3JlcyBlbiBkaXN0aW50b3MgZ3J1cG9zLg0KRWwgb2JqZXRpdm8gZXMgZGV0ZXJtaW5hciBzaSBsYSBkaXN0YW5jaWEgZXN0w6EgcmVsYWNpb25hZGEgY29uIGxhIGxvbmdpdHVkIGRlIHBpZXJuYS4gU2UgcG9kcsOtYSBlc3BlcmFyIHF1ZSBsb3MganVnYWRvcmVzIGRlIHBpZXJuYXMgbcOhcyBsYXJnYXMgdGVuZ2FuIHVuYSBjb250ZXh0dXJhIGbDrXNpY2EgbWF5b3IgeSBwb3IgbG8gdGFudG8gcG9zZWFuIG1heW9yIHBvdGVuY2lhIGFsIHBhdGVhci4NCg0KUmVzdW1lbiB5IHZpc3VhbGl6YWNpw7NuIGRlIGxvcyBkYXRvczoNCmBgYHtyfQ0Kc3VtbWFyeShmdXRib2wpDQpmdXRib2wNCmBgYA0KDQoNCiMjIEdSw4FGSUNPIERFIEJBUlJBUw0KDQpgYGB7cn0NCnRhYmxhX2ZyZWMgPC0gY291bnQoZnV0Ym9sLCBsb25ncCwgbmFtZSA9ICJGcmVjdWVuY2lhIikNCnRhYmxhX2ZyZWMNCnRhYmxhX2ZyZWM9bXV0YXRlKHRhYmxhX2ZyZWMsIA0KICAgICAgICAgICAgICAgICAgcG9yY2VudGFqZV9ldGlxdWV0YT1zdHJfYyhhcy5jaGFyYWN0ZXIocm91bmQodGFibGFfZnJlYyRGcmVjdWVuY2lhL3N1bSh0YWJsYV9mcmVjJEZyZWN1ZW5jaWEpKjEwMCkpLCIlIiksDQogICAgICAgICAgICAgICAgICBwb3JjZW50YWplPXRhYmxhX2ZyZWMkRnJlY3VlbmNpYS9zdW0odGFibGFfZnJlYyRGcmVjdWVuY2lhKSoxMDAsDQogICAgICAgICAgICAgICAgICBsb25ncD1mYWN0b3IobG9uZ3AsIGxldmVscz1jKCIxLjIxIG0geSArIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMS4xMSBhIDEuMjAgbSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEuMDEgYSAxLjEwIG0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwLjkxIGEgMS4wMCBtIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMC44MSBhIDAuOTAgbSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjwgMC44MSBtIikpDQogICAgICAgICAgICAgICAgICApDQpgYGANCg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gdGFibGFfZnJlYykgKw0KICBjb29yZF9mbGlwKCkrDQogIGFlcyh4ID0gbG9uZ3AsIHkgPSBwb3JjZW50YWplLCBmaWxsPXBvcmNlbnRhamUpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJsaWdodGJsdWUiLCBoaWdoID0gImJsdWUiKSArDQogIGdlb21fbGFiZWwoDQogICAgYWVzKGxhYmVsID0gcG9yY2VudGFqZV9ldGlxdWV0YSksIA0KICAgIHZqdXN0ID0gMC41LCBzaXplID0gNSxoanVzdD0xLA0KICAgIGNvbG9yID0gImJsYWNrIiwNCiAgICBwb3NpdGlvbiA9ICJpZGVudGl0eSINCiAgKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNjAsIDEwKSkgKw0KICBsYWJzKHggPSAiTG9uZ2l0dWQgZGUgcGllcm5hIiwgeSA9ICJQb3JjZW50YWplIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQpFc3RlIGdyw6FmaWNvIHRpZW5lIG9yaWVudGFjacOzbiBob3Jpem9udGFsLCBlbCBjb2xvciBkZSBjYWRhIGJhcnJhIGVzdMOhIGFzb2NpYWRvIGEgc3UgbWFnbml0dWQgeSBlbCBlamUgWCByZXByZXNlbnRhIGxvcyBwb3JjZW50YWplcyBkZSBjYWRhIGNhdGVnb3LDrWEgZGUgbG9uZ2l0dWQgZGUgcGllcm5hLg0KU2Ugb2JzZXJ2YSBxdWUgbGEgY2F0ZWdvcsOtYSBkZSBsb25naXR1ZCBkZSBwaWVybmEgbcOhcyBwb3B1bGFyIGVzICI8MC44MSBtIiBjb24gYXByb3hpbWFkYW1lbnRlIHVuIDE5JSwgc2VndWlkYSBwb3IgIjEuMTEgYSAxLjIwIG0iIGNvbiBhcHJveGltYWRhbWVudGUgdW4gMTclLg0KDQojIyBNT1NBSUNPUw0KDQpTZSB0b21hIGxhIHZhcmlhYmxlIGRpc3QgZGUgbG9zIGRhdG9zIGZ1dGJvbCB5IHNlIGNvbnZpZXJ0ZSBlbiB1biBmYWN0b3IgY29uIGRvcyBuaXZlbGVzOiDigJxkaXN0YW5jaWEgcmVjb3JyaWRhIG1lbm9yIGEgNTAgbXRzLuKAnSB5IOKAnGRpc3RhbmNpYSBtYXlvciBvIGlndWFsIGEgNTAgbXRzLuKAnS4NCg0KQSBwYXJ0aXIgZGUgZWxsbyBzZSByZWFsaXphbiBncsOhZmljb3MgZGUgbW9zYWljbywgY29uIHRlc3QgZGUgaW5kZXBlbmRlbmNpYSBpbmNsdWlkbywgcGFyYSBjb21wYXJhciBncnVwb3MgZGUgbG9uZ2l0dWRlcyBkZSBwaWVybmEgc3VjZXNpdm9zIChjb21wYXJhY2lvbmVzIGRlIGEgMikuDQoNCiMjIyAxZXIgdnMgMmRvIGdydXBvDQoNCmBgYHtyfQ0KZnV0Ym9sMj1maWx0ZXIoZnV0Ym9sLChsb25ncD09IjwgMC44MSBtIil8KGxvbmdwPT0iMC44MSBhIDAuOTAgbSIpKQ0KZnV0Ym9sMj1tdXRhdGUoZnV0Ym9sMiwNCiAgICAgICAgICAgICAgIGRpc3QyPWlmZWxzZShmdXRib2wyJGRpc3Q8NTAsIlszMDs1MCkiLCJbNTA7MTE1KSIpDQogICAgICAgICAgICAgICApDQpgYGANCg0KDQpgYGB7cn0NCm1vc2FpYyggfiBsb25ncCArIGRpc3QyLCBkYXRhID0gZnV0Ym9sMiwgZGlyZWN0aW9uID0gInYiLCBzaGFkZSA9IFRSVUUpDQpgYGANCg0KDQpTZSBvYnNlcnZhIHF1ZSBsb3MganVnYWRvcmVzIGNvbiB1bmEgbG9uZ2l0dWQgZGUgcGllcm5hICI8IDAuODEgbSIgcGF0ZWFuIHVuYSBkaXN0YW5jaWEgZW50cmUgWzUwOzExNSkgZW4gbWVub3IgcHJvcG9yY2nDs24gcXVlIGxvcyBxdWUgdGllbmVuIHVuYSBsb25naXR1ZCBkZSBwaWVybmEgZGUgIjAuODEgYSAwLjkwIG0iIHBlcm8gZXMgYWwgcmV2w6lzIHBhcmEgdW5hIGRpc3RhbmNpYSBlbnRyZSAiWzMwOzUwKSINCg0KJEhfMCkkIExhIGxvbmdpdHVkIGRlIHBpZXJuYSB5IGxhIGRpc3RhbmNpYSBzb24gaW5kZXBlbmRpZW50ZXMNCg0KJEhfMSkkIExhIGxvbmdpdHVkIGRlIHBpZXJuYSB5IGxhIGRpc3RhbmNpYSBubyBzb24gaW5kZXBlbmRpZW50ZXMNCg0KRW4gYmFzZSBhIGxhIGV2aWRlbmNpYSBtdWVzdHJhbCB5IGNvbiB1biBuaXZlbCBkZSBzaWduaWZpY2FjacOzbiBkZWwgNSUgc2UgY29uY2x1eWUgcXVlIHNlIHJlY2hhemEgbGEgaGlww7N0ZXNpcyBudWxhIGRlIGluZGVwZW5kZW5jaWEgZW50cmUgbGEgbG9uZ2l0dWQgZGUgcGllcm5hIHkgbGEgZGlzdGFuY2lhIHlhIHF1ZSBzZSBvYnNlcnZhIHVuIHZhbG9yIGRlIHByb2JhYmlsaWRhZCBhc29jaWFkbyBtZW5vciBhIDAuMDUuIEVzdGFzIHZhcmlhYmxlcyBzZSBkaXN0cmlidXllbiBkZSBkaWZlcmVudGUgZm9ybWEgcGFyYSBsb3MgZGlzdGludG9zIG5pdmVsZXMgZGUgbGEgb3RyYS4NCg0KDQojIyMgMmVyIHZzIDNlciBncnVwbw0KDQpgYGB7cn0NCmZ1dGJvbDM9ZmlsdGVyKGZ1dGJvbCwobG9uZ3A9PSIwLjgxIGEgMC45MCBtIil8KGxvbmdwPT0iMC45MSBhIDEuMDAgbSIpKQ0KZnV0Ym9sMz1tdXRhdGUoZnV0Ym9sMywNCiAgICAgICAgICAgICAgIGRpc3QzPWlmZWxzZShmdXRib2wzJGRpc3Q8NTAsIlszMDs1MCkiLCJbNTA7MTE1KSIpDQopDQpgYGANCg0KYGBge3J9DQptb3NhaWMoIH4gbG9uZ3AgKyBkaXN0MywgZGF0YSA9IGZ1dGJvbDMsIGRpcmVjdGlvbiA9ICJ2Iiwgc2hhZGUgPSBUUlVFKQ0KYGBgDQoNClNlIG9ic2VydmEgcXVlIGxvcyBqdWdhZG9yZXMgY29uIHVuYSBsb25naXR1ZCBkZSBwaWVybmEgIjAuODEgYSAwLjkwIG0iIHBhdGVhbiB1bmEgZGlzdGFuY2lhIGVudHJlIFs1MDsxMTUpIGVuIG1lbm9yIHByb3BvcmNpw7NuIHF1ZSBsb3MgcXVlIHRpZW5lbiB1bmEgbG9uZ2l0dWQgZGUgcGllcm5hIGRlICIwLjkxIGEgMS4wMCBtIiBwZXJvIGVzIGFsIHJldsOpcyBwYXJhIHVuYSBkaXN0YW5jaWEgZW50cmUgIlszMDs1MCkiLg0KDQokSF8wKSQgTGEgbG9uZ2l0dWQgZGUgcGllcm5hIHkgbGEgZGlzdGFuY2lhIHNvbiBpbmRlcGVuZGllbnRlcw0KDQokSF8xKSQgTGEgbG9uZ2l0dWQgZGUgcGllcm5hIHkgbGEgZGlzdGFuY2lhIG5vIHNvbiBpbmRlcGVuZGllbnRlcw0KDQpFbiBiYXNlIGEgbGEgZXZpZGVuY2lhIG11ZXN0cmFsIHkgY29uIHVuIG5pdmVsIGRlIHNpZ25pZmljYWNpw7NuIGRlbCA1JSBzZSBjb25jbHV5ZSBxdWUgc2UgcmVjaGF6YSBsYSBoaXDDs3Rlc2lzIG51bGEgZGUgaW5kZXBlbmRlbmNpYSBlbnRyZSBsYSBsb25naXR1ZCBkZSBwaWVybmEgeSBsYSBkaXN0YW5jaWEgeWEgcXVlIHNlIG9ic2VydmEgdW4gdmFsb3IgZGUgcHJvYmFiaWxpZGFkIGFzb2NpYWRvIG1lbm9yIGEgMC4wNS4gRXN0YXMgdmFyaWFibGVzIHNlIGRpc3RyaWJ1eWVuIGRlIGRpZmVyZW50ZSBmb3JtYSBwYXJhIGxvcyBkaXN0aW50b3Mgbml2ZWxlcyBkZSBsYSBvdHJhLg0KDQojIyMgM2VyIHZzIDR0byBncnVwbw0KDQpgYGB7cn0NCmZ1dGJvbDQ9ZmlsdGVyKGZ1dGJvbCwobG9uZ3A9PSIwLjkxIGEgMS4wMCBtIil8KGxvbmdwPT0iMS4wMSBhIDEuMTAgbSIpKQ0KZnV0Ym9sND1tdXRhdGUoZnV0Ym9sNCwNCiAgICAgICAgICAgICAgIGRpc3Q0PWlmZWxzZShmdXRib2w0JGRpc3Q8NTAsIlszMDs1MCkiLCJbNTA7MTE1KSIpDQopDQpgYGANCg0KYGBge3J9DQptb3NhaWMoIH4gbG9uZ3AgKyBkaXN0NCwgZGF0YSA9IGZ1dGJvbDQsIGRpcmVjdGlvbiA9ICJ2Iiwgc2hhZGUgPSBUUlVFKQ0KYGBgDQoNClNlIG9ic2VydmEgcXVlIGxvcyBqdWdhZG9yZXMgY29uIHVuYSBsb25naXR1ZCBkZSBwaWVybmEgIjAuOTEgYSAxLjAwIG0iIHBhdGVhbiB1bmEgZGlzdGFuY2lhIGVudHJlIFs1MDsxMTUpIGVuIHByb3BvcmNpw7NuIG11eSBzaW1pbGFyIHF1ZSBsb3MgcXVlIHRpZW5lbiB1bmEgbG9uZ2l0dWQgZGUgcGllcm5hIGRlICIxLjAxIGEgMS4xMCBtIiB5IHNlIG9ic2VydmEgbG8gbWlzbW8gcGFyYSB1bmEgZGlzdGFuY2lhIGVudHJlICJbMzA7NTApIi4NCg0KJEhfMCkkIExhIGxvbmdpdHVkIGRlIHBpZXJuYSB5IGxhIGRpc3RhbmNpYSBzb24gaW5kZXBlbmRpZW50ZXMNCg0KJEhfMSkkIExhIGxvbmdpdHVkIGRlIHBpZXJuYSB5IGxhIGRpc3RhbmNpYSBubyBzb24gaW5kZXBlbmRpZW50ZXMNCg0KRW4gYmFzZSBhIGxhIGV2aWRlbmNpYSBtdWVzdHJhbCB5IGNvbiB1biBuaXZlbCBkZSBzaWduaWZpY2FjacOzbiBkZWwgNSUgc2UgY29uY2x1eWUgcXVlIG5vIHNlIHJlY2hhemEgbGEgaGlww7N0ZXNpcyBudWxhIGRlIGluZGVwZW5kZW5jaWEgZW50cmUgbGEgbG9uZ2l0dWQgZGUgcGllcm5hIHkgbGEgZGlzdGFuY2lhIHlhIHF1ZSBzZSBvYnNlcnZhIHVuIHZhbG9yIGRlIHByb2JhYmlsaWRhZCBhc29jaWFkbyBtYXlvciBhIDAuMDUuIERlYmUgdGVuZXJzZSBlbiBjdWVudGEgZWwgY3VtcGxpbWllbnRvIGRlIGxvcyBzdXB1ZXN0b3MgZGVsIHRlc3QgZGUgaW5kZXBlbmRlbmNpYS4NCg0KDQojIyMgNHRvIHZzIDV0byBncnVwbw0KDQpgYGB7cn0NCmZ1dGJvbDU9ZmlsdGVyKGZ1dGJvbCwobG9uZ3A9PSIxLjAxIGEgMS4xMCBtIil8KGxvbmdwPT0iMS4xMSBhIDEuMjAgbSIpKQ0KZnV0Ym9sNT1tdXRhdGUoZnV0Ym9sNSwNCiAgICAgICAgICAgICAgIGRpc3Q1PWlmZWxzZShmdXRib2w1JGRpc3Q8NTAsIlszMDs1MCkiLCJbNTA7MTE1KSIpDQopDQpgYGANCg0KYGBge3J9DQptb3NhaWMoIH4gbG9uZ3AgKyBkaXN0NSwgZGF0YSA9IGZ1dGJvbDUsIGRpcmVjdGlvbiA9ICJ2Iiwgc2hhZGUgPSBUUlVFKQ0KYGBgDQoNClNlIG9ic2VydmEgcXVlIGxvcyBqdWdhZG9yZXMgY29uIHVuYSBsb25naXR1ZCBkZSBwaWVybmEgIjEuMDEgYSAxLjEwIG0iIHBhdGVhbiB1bmEgZGlzdGFuY2lhIGVudHJlIFs1MDsxMTUpIHByb3BvcmNpw7NuIHNpbWlsYXIgYSBsb3MgcXVlIHRpZW5lbiB1bmEgbG9uZ2l0dWQgZGUgcGllcm5hIGRlICIxLjExIGEgMS4yMCBtIiBwZXJvIHBhcmVjZSBzZXIgbGV2ZW1lbnRlIG1heW9yIGxhIGNhbnRpZGFkIGRlIGp1Z2Fkb3JlcyBjb24gbG9uZ2l0dWQgZGUgcGllcm5hICIxLjAxIGEgMS4xMCBtIiBxdWUgcGF0ZWFuIHVuYSBkaXN0YW5jaWEgZW50cmUgIlszMDs1MCkiLg0KDQokSF8wKSQgTGEgbG9uZ2l0dWQgZGUgcGllcm5hIHkgbGEgZGlzdGFuY2lhIHNvbiBpbmRlcGVuZGllbnRlcw0KDQokSF8xKSQgTGEgbG9uZ2l0dWQgZGUgcGllcm5hIHkgbGEgZGlzdGFuY2lhIG5vIHNvbiBpbmRlcGVuZGllbnRlcw0KDQpFbiBiYXNlIGEgbGEgZXZpZGVuY2lhIG11ZXN0cmFsIHkgY29uIHVuIG5pdmVsIGRlIHNpZ25pZmljYWNpw7NuIGRlbCA1JSBzZSBjb25jbHV5ZSBxdWUgbm8gc2UgcmVjaGF6YSBsYSBoaXDDs3Rlc2lzIG51bGEgZGUgaW5kZXBlbmRlbmNpYSBlbnRyZSBsYSBsb25naXR1ZCBkZSBwaWVybmEgeSBsYSBkaXN0YW5jaWEgeWEgcXVlIHNlIG9ic2VydmEgdW4gdmFsb3IgZGUgcHJvYmFiaWxpZGFkIGFzb2NpYWRvIG1heW9yIGEgMC4wNS4gRGViZSB0ZW5lcnNlIGVuIGN1ZW50YSBlbCBjdW1wbGltaWVudG8gZGUgbG9zIHN1cHVlc3RvcyBkZWwgdGVzdCBkZSBpbmRlcGVuZGVuY2lhLg0KDQojIyMgNXRvIHZzIDZ0byBncnVwbw0KDQpgYGB7cn0NCmZ1dGJvbDY9ZmlsdGVyKGZ1dGJvbCwobG9uZ3A9PSIxLjExIGEgMS4yMCBtIil8KGxvbmdwPT0iMS4yMSBtIHkgKyIpKQ0KZnV0Ym9sNj1tdXRhdGUoZnV0Ym9sNiwNCiAgICAgICAgICAgICAgIGRpc3Q2PWlmZWxzZShmdXRib2w2JGRpc3Q8NTAsIlszMDs1MCkiLCJbNTA7MTE1KSIpDQopDQpgYGANCg0KYGBge3J9DQptb3NhaWMoIH4gbG9uZ3AgKyBkaXN0NiwgZGF0YSA9IGZ1dGJvbDYsIGRpcmVjdGlvbiA9ICJ2Iiwgc2hhZGUgPSBUUlVFKQ0KYGBgDQoNClNlIG9ic2VydmEgcXVlIHRvZG9zIGxvcyBqdWdhZG9yZXMgY29uIGxvbmdpdHVkIGRlIHBpZXJuYSAiMS4xMSBhIDEuMjAgbSIgeSAiMS4yMSBtIHkgKyIgcGF0ZWFuIGxhIHBlbG90YSBhIHVuYSBkaXN0YW5jaWEgZW50cmUgNTAgeSAxMTUgbS4gDQoNCiRIXzApJCBMYSBsb25naXR1ZCBkZSBwaWVybmEgeSBsYSBkaXN0YW5jaWEgc29uIGluZGVwZW5kaWVudGVzDQoNCiRIXzEpJCBMYSBsb25naXR1ZCBkZSBwaWVybmEgeSBsYSBkaXN0YW5jaWEgbm8gc29uIGluZGVwZW5kaWVudGVzDQoNCkVuIGJhc2UgYSBsYSBldmlkZW5jaWEgbXVlc3RyYWwgeSBjb24gdW4gbml2ZWwgZGUgc2lnbmlmaWNhY2nDs24gZGVsIDUlIHNlIGNvbmNsdXllIHF1ZSBubyBzZSByZWNoYXphIGxhIGhpcMOzdGVzaXMgbnVsYSBkZSBpbmRlcGVuZGVuY2lhIGVudHJlIGxhIGxvbmdpdHVkIGRlIHBpZXJuYSB5IGxhIGRpc3RhbmNpYSB5YSBxdWUgc2Ugb2JzZXJ2YSB1biB2YWxvciBkZSBwcm9iYWJpbGlkYWQgYXNvY2lhZG8gbWF5b3IgYSAwLjA1LiBEZWJlIHRlbmVyc2UgZW4gY3VlbnRhIGVsIGN1bXBsaW1pZW50byBkZSBsb3Mgc3VwdWVzdG9zIGRlbCB0ZXN0IGRlIGluZGVwZW5kZW5jaWEuDQoNCg0KIyMgQUxMVVZJQUwNCg0KUGFyYSBlc3RlIGdyw6FmaWNvIHNlIHV0aWxpemFuIGRhdG9zIHNvYnJlIHRvbmVsYWRhcyBwcm9kdWNpZGFzIGVuIEFyZ2VudGluYSBkZSB2YXJpb3MgdGlwb3MgZGUgY3VsdGl2b3MgKHNvamEsIHRyaWdvLCBjZWJhZGEsIGV0Yy4pIGRlc2FncmVnYWRvcyBhIG5pdmVsIHByb3ZpbmNpYWwgeSBkZXBhcnRhbWVudGFsIHBhcmEgbGEgY2FtcGHDsWEgYWdyw61jb2xhIDIwMTkvMjAuDQoNCkEgcGFydGlyIGRlIGVzdG9zIHNlIGdlbmVyYSB1biBncsOhZmljbyBhbGx1dmlhbCBwYXJhIGNvbXBhcmFyIGxhcyBwcm9kdWNjaW9uZXMgZGUgc29yZ28geSBnaXJhc29sIGVuIGxhcyBwcm92aW5jaWFzIGRlIFNhbnRhIEZlLCBDw7NyZG9iYSB5IExhIFBhbXBhLg0KDQpSZXN1bWVuIHkgdmlzdWFsaXphY2nDs24gZGUgbG9zIGRhdG9zOg0KDQpgYGB7cn0NCmxvYWQoIkM6L1VzZXJzL1RlbXAvRG9jdW1lbnRzLzEgRmFjdWx0YWQvVGVyY2Vyby9UQUUvVFAgNC9jdWx0aXZvcy5SRGF0YSIpDQpzdW1tYXJ5KGN1bHRpdm9zKQ0KY3VsdGl2b3MNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQpjdWx0aXZvczIgPC0gY3VsdGl2b3MgJT4lIA0KICAgICBmaWx0ZXIocHJvdj09IkNPUkRPQkEifHByb3Y9PSJMQSBQQU1QQSJ8cHJvdj09IlNBTlRBIEZFIikgJT4lDQogICAgIGZpbHRlcihjdWx0aXZvPT0iR2lyYXNvbCJ8Y3VsdGl2bz09IlNvcmdvIikgJT4lDQogICAgIGdyb3VwX2J5KHByb3YsY3VsdGl2bykgJT4lIA0KICAgICBzdW1tYXJpc2UocHJvZCA9IHN1bShwcm9kKSkNCmN1bHRpdm9zMj1tdXRhdGUoY3VsdGl2b3MyLCJUbi4gKDEwMC4wMDApIj1wcm9kLzEwMDAwMCkNCmBgYA0KDQoNCmBgYHtyfQ0KY3VsdGl2b3MyICU+JSANCiAgI2FzLmRhdGEuZnJhbWUoKSAlPiUgDQogIGdncGxvdCgpICsgDQogIGFlcyhheGlzMSA9IHByb3YsIGF4aXMyID0gY3VsdGl2bywgZmlsbCA9IGBUbi4gKDEwMC4wMDApYCwgeSA9IHByb2QpICsNCiAgZ2VvbV9hbGx1dml1bSgpICsgI2ZsdWpvcw0KICBnZW9tX3N0cmF0dW0oICNjb2x1bW5hcw0KICAgIGZpbGwgPSAiYmxhY2siLCANCiAgICBjb2xvciA9ICJsaWdodGdyZXkiLA0KICAgIHdpZHRoID0gMC4xDQogICkgKyANCiAgZ2VvbV9sYWJlbCggI2V0aXF1ZXRhcw0KICAgIHN0YXQgPSAic3RyYXR1bSIsIA0KICAgIGFlcyhsYWJlbCA9IGFmdGVyX3N0YXQoc3RyYXR1bSkpLA0KICAgIGZpbGwgPSAid2hpdGUiLA0KICAgIHNpemUgPSAyDQogICkgKyANCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJQcm92aW5jaWEiLCAiQ3VsdGl2byIpLCBleHBhbmQgPSBjKDAsIDApKSArDQogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlByb2R1Y2Npb24gZW4gKDEwMC4wMDAgVG4uKSIsIGJyZWFrcyA9IHNlcSgwLCAxNTAwMDAwLCA1MDAwMDApLCBsYWJlbHMgPXNlcSgwLCAxNSwgNSkgKSsNCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJ5ZWxsb3ciLCBoaWdoID0gInJlZCIpDQoNCmBgYA0KDQoNCkEgcGFydGlyIGRlIGVzdGUgZ3LDoWZpY28gc2Ugb2JzZXJ2YSBxdWUgU2FudGEgRmUgZXMgbGEgcHJvdmluY2lhIHF1ZSB0aWVuZSBtYXlvciBwcm9kdWNjacOzbiBkZSBTb3JnbyB5IGRlIEdpcmFzb2wsIHkgcXVlIGVzdGEgZXMgc2ltaWxhciBwYXJhIGFtYm9zIGN1bHRpdm9zLiBNaWVudHJhcyBxdWUgQ8OzcmRvYmEgeSBMYSBQYW1wYSBwcm9kdWNlbiBjYW50aWRhZGVzIGRpZmVyZW50ZXMgZGUgU29yZ28geSBHaXJhc29sIChDw7NyZG9iYSBwcm9kdWNlIG1heW9yIGNhbnRpZGFkIGRlIFNvcmdvIHkgTGEgUGFtcGEgcHJvZHVjZSBtYXlvciBjYW50aWRhZCBkZSBHaXJhc29sKS4NCg0KIyMgVFJFRU1BUFMNCg0KUGFyYSBlc3RlIGdyw6FmaWNvIHNlIHV0aWxpemEgZWwgY29uanVudG8gZGUgZGF0b3MgVGl0YW5pYyBkZWwgcGFxdWV0ZSBkZSBSIEJhc2UgZGF0YXNldHMgcXVlIGNvbnRpZW5lIGVsIHBvcmNlbnRhamUgZGUgcGFzYWplcm9zL2FzIHF1ZSBzb2JyZXZpdmllcm9uIGEgbGEgdHJhZ2VkaWEgZGVsIGJhcmNvLCBkZXNhZ3JlZ2Fkb3Mgc2Vnw7puIGVkYWQsIGfDqW5lcm8geSBjbGFzZSBlbiBsYSBxdWUgdmlhamFiYW4uDQoNClJlc3VtZW4geSB2aXN1YWxpemFjacOzbiBkZSBsb3MgZGF0b3M6DQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpzdW1tYXJ5KFRpdGFuaWMpDQpUaXRhbmljDQpgYGANCg0KQSBwYXJ0aXIgZGUgZXN0b3MgZGF0b3Mgc2UgcmVwbGljYSB1biB0cmVlbWFwIGRpbsOhbWljbyBxdWUgbXVlc3RyYSBsb3MgcG9yY2VudGFqZXMgZGUgc3VwZXJ2aXZlbmNpYSBzZWfDum4gbGEgY2xhc2UgZW4gbGEgcXVlIHZpYWphYmEgY2FkYSBwYXNhamVybzoNCg0KYGBge3J9DQp0aXRhbmljPWFzLmRhdGEuZnJhbWUoVGl0YW5pYykNCnRpdGFuaWM9bXV0YXRlKHRpdGFuaWMsU3Vydml2ZWQ9aWZlbHNlKFN1cnZpdmVkPT0iTm8iLCJObyBTb2JyZXZpdmnDsyIsIlNvYnJldml2acOzIikpDQoNCnRpdGFuaWMyIDwtIHRpdGFuaWMgJT4lIA0KICBncm91cF9ieShDbGFzcywgU3Vydml2ZWQpICU+JSANCiAgc3VtbWFyaXNlKEZyZXEgPSBzdW0oRnJlcSkpICU+JSANCiAgdW5ncm91cCgpDQoNCnRpdGFuaWNfdG90IDwtIHRpdGFuaWMyICU+JSANCiAgZ3JvdXBfYnkoQ2xhc3MpICU+JSANCiAgc3VtbWFyaXNlKEZyZXEgPSBzdW0oRnJlcSkpJT4lDQogIHVuZ3JvdXAoKSAlPiUgDQogIHJlbmFtZShTdXJ2aXZlZCA9IENsYXNzKSAlPiUgDQogIG11dGF0ZShDbGFzcyA9ICJUb3RhbCBUaXRhbmljIikgJT4lDQogIGJpbmRfcm93cyh0aXRhbmljMiklPiUNCiAgbXV0YXRlKGV0aXEgPSBpZmVsc2UoQ2xhc3MgIT0gIlRvdGFsIFRpdGFuaWMiLA0KICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoU3Vydml2ZWQsICJfIiwgQ2xhc3MpLA0KICAgICAgICAgICAgICAgICAgICAgICBhcy5jaGFyYWN0ZXIoU3Vydml2ZWQpKSkNCmBgYA0KDQpgYGB7cn0NCnBsb3RfbHkoDQogIHR5cGUgPSAidHJlZW1hcCIsDQogIGxhYmVscyA9IHRpdGFuaWNfdG90JGV0aXEsICN2YXJpYWJsZSBkZSBtZW5vciBqZXJhcnF1w61hIChldGlxdWV0YSDDum5pY2EpDQogIHBhcmVudHMgPSB0aXRhbmljX3RvdCRDbGFzcywgI3ZhcmlhYmxlIGRlIG1heW9yIGplcmFycXXDrWENCiAgdmFsdWVzID0gdGl0YW5pY190b3QkRnJlcSwgI3RhbWHDsW8gZGUgY2FkYSByZWN0w6FuZ3Vsbw0KICBob3ZlcmluZm8gPSAibGFiZWwrdmFsdWUrcGVyY2VudCBwYXJlbnQrcGVyY2VudCByb290IiwNCiAgdGV4dGluZm8gPSAibGFiZWwrdmFsdWUrcGVyY2VudCBwYXJlbnQrcGVyY2VudCByb290Ig0KKSU+JQ0KICBhZGRfdHJhY2UoYnJhbmNodmFsdWVzID0gInRvdGFsIiwgbmFtZSA9ICIiKQ0KDQpgYGANCg0KDQpBIHBhcnRpciBkZSBlc3RlIGdyw6FmaWNvIHNlIG9ic2VydmEgcXVlIGRlIGxhIHRyaXB1bGFjacOzbiBubyBzb2JyZXZpdmllcm9uIDY3MyBwYXNhamVyb3MgcXVlIHJlcHJlc2VudGFuIGVsIDMxJSBkZWwgdG90YWwgZGUgbG9zIHBhc2FqZXJvcyBkZWwgVGl0YW5pYyB5IGVsIDc2JSBkZSBsYSB0cmlwdWxhY2nDs24uIE1pZW50cmFzIHF1ZSwgc29icmV2aXZpZXJvbiAyMTIgcGFzYWplcm9zIGRlIGxhIHRyaXB1bGFjacOzbi4NCkRlIGxvcyBwYXNhamVyb3MgcXVlIHZpYWphcm9uIGVuIHByaW1lcmEgY2xhc2Ugc29icmV2aXZpw7MgZWwgNjIlICgyMDMgcGFzYWplcm9zKSwgcXVlIHJlcHJlc2VudGEgZWwgOSUgZGVsIHRvdGFsIGRlIHBhc2FqZXJvcy4gU2llbmRvIG1heW9yIGVsIHBvcmNlbnRhamUgZGUgcGFzYWplcm9zIHF1ZSBzb2JyZXZpdmllcm9uLiAgDQpQYXJhIGxhIHNlZ3VuZGEgeSB0ZXJjZXJhIGNsYXNlLCBmdWUgbWF5b3IgZWwgcG9yY2VudGFqZSBkZSBwYXNhamVyb3MgcXVlIG5vIHNvYnJldml2aWVyb24sIGFsIGlndWFsIHF1ZSBwYXJhIGxhIHRyaXB1bGFjacOzbi4NCg0KIyBNQVBBUw0KDQpMYSBnZW9ycmVmZXJlbmNpYSBlcyB1bmEgZGlzY2lwbGluYSBsaWdhZGEgYWwgYW7DoWxpc2lzIGRlIGRhdG9zIHJlY29sZWN0YWRvcyBhIG5pdmVsIGdlb2dyw6FmaWNvLiBFc3RhIGNhcmFjdGVyw61zdGljYSBpbXBsaWNhIHF1ZSBsYSBpbmZvcm1hY2nDs24gcXVlIHBvc2VlbW9zIHB1ZWRlIHZpc3VhbGl6YXJzZSBkZSBtYW5lcmEgbcOhcyBlZmljaWVudGUgZGVzZGUgdW5hIHBlcnNwZWN0aXZhIGVzcGFjaWFsLCBlcyBkZWNpciwgcmVwcmVzZW50YW5kbyBsb3MgZGF0b3MgZW4gbWFwYXMgeSBubyBtZWRpYW50ZSBncsOhZmljb3MsIHRhYmxhcyB1IG90cm9zIGluc3RydW1lbnRvcy4NCkVuIGVzdGEgcGFydGUgZGVsIHRyYWJham8gc2UgcmVhbGl6YXLDoW4gZXN0YSBjbGFzZSBkZSBtYXBhcy4NCg0KTGFzIGxpYnJlcsOtYXMgYSB1dGlsaXphciBzb246DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQ0KI01hcGFzDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeSh0bWFwKQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShzcERhdGEpDQojVmFyaW9zDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzdHJpbmdyKQ0KYGBgDQoNClBhcmEgcmVhbGl6YXIgZXN0b3MgZ3LDoWZpY29zIHNlIHV0aWxpemEgZWwgY29uanVudG8gZGUgZGF0b3Mgd29ybGQgZGVsIHBhcXVldGUgc3BEYXRhLiBDYWRhIHVuYSBkZSBsYXMgMTc3IGZpbGFzIGRlIGVzdGEgYmFzZSBjb3JyZXNwb25kZSBhIHVuIHBhw61zIGRpZmVyZW50ZSwgcGFyYSBsb3MgY3VhbGVzIHNlIHJlZ2lzdHJhbiBkaXZlcnNhcyB2YXJpYWJsZXM6IG5vbWJyZSwgY29udGluZW50ZSwgc3VwZXJmaWNpZSwgcG9ibGFjacOzbiwgZXRjLg0KDQpSZXN1bWVuIHkgdmlzdWFsaXphY2nDs24gZGUgbG9zIGRhdG9zOg0KDQpgYGB7cn0NCnN1bW1hcnkod29ybGQpDQp3b3JsZA0KYGBgDQoNCiMjIFBhcXVldGUgU0YNCg0KVXNhbmRvIGZ1bmNpb25lcyBkZWwgcGFxdWV0ZSBzZiwgc2UgZ3JhZmljYW4gbG9zIHBhw61zZXMgZGUgQW3DqXJpY2EgZGVsIFN1ciBhc2lnbmFuZG8gY29sb3JlcyBkZSBhY3VlcmRvIGEgc3UgZXNwZXJhbnphIGRlIHZpZGEuIA0KDQpgYGB7cn0NCmRhdGEod29ybGQpDQpzdWRhbWVyaWNhPSB3b3JsZCAlPiUgZmlsdGVyKGNvbnRpbmVudCA9PSAiU291dGggQW1lcmljYSIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHN1ZGFtZXJpY2EpICsNCiAgYWVzKGZpbGwgPSBsaWZlRXhwKSArDQogIGdndGl0bGUoIkVzcGVyYW56YSBkZSBWaWRhIChlbiBBw7FvcykgcG9yIFBhw61zIC0gRGF0b3MgMjAxNCIpKw0KICBnZW9tX3NmKCkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJyZWQiLCBoaWdoID0gImdyZWVuIikgKw0KICB0aGVtZV9idygpDQpgYGANCg0KQSBwYXJ0aXIgZGUgZXN0ZSBtYXBhIHNlIG9ic2VydmEgcXVlIENoaWxlIGVzIGVsIHBhw61zIGNvbiBtYXlvciBlc3BlcmFuemEgZGUgdmlkYSBlbnRyZSBsb3MgcGHDrXNlcyBkZSBBbcOpcmljYSBkZWwgU3VyLCBzZWd1aWRvIHBvciBVcnVndWF5IHkgQXJnZW50aW5hLiBNaWVudHJhcyBxdWUsIEd1YXlhbmEgeSBCb2xpdmlhIHNvbiBsb3MgcGHDrXNlcyBjb24gbWVub3IgZXNwZXJhbnphIGRlIHZpZGEuDQoNCiMjIFBhcXVldGUgVE1BUA0KDQpTZSByZWFsaXphIHVuIG1hcGEgdXNhbmRvIGZ1bmNpb25lcyBkZWwgcGFxdWV0ZSB0bWFwLCBkb25kZSBzZSBjb21wYXJhbiBsb3MgdmFsb3JlcyBkZSBQQkkgcGVyIGPDoXBpdGEgZGUgbG9zIHBhw61zZXMgYWZyaWNhbm9zOg0KDQpgYGB7cn0NCnRtYXBfbW9kZSgicGxvdCIpDQphZnJpY2E9IHdvcmxkICU+JSBmaWx0ZXIoY29udGluZW50ID09ICJBZnJpY2EiKQ0KDQphZnJpY2EgJT4lIA0KICB0bV9zaGFwZSgpICsgDQogIHRtX2ZpbGwoaWQgPSAibmFtZV9sb25nIiwgY29sID0gImdkcFBlcmNhcCIpICsNCiAgdG1fc3R5bGUoImNvYmFsdCIpICsNCiAgdG1fYm9yZGVycygiYmxhY2siLCBsd2QgPSAxKSArIA0KICB0bV9taW5pbWFwKCkgKw0KICB0bV9iYXNlbWFwKCJTdGFtZW4uVG9uZXJCYWNrZ3JvdW5kIikrDQogIHRtX3RleHQoICJuYW1lX2xvbmciLCBzaXplPS42KQ0KYGBgDQoNCg0KDQpBIHBhcnRpciBkZSBlc3RlIG1hcGEgc2Ugb2JzZXJ2YSBxdWUgbG9zIHBhw61zZXMgY29uIG1heW9yIFBCSSBwZXIgY8OhcGl0YSBlbiDDgWZyaWNhIHNvbiBHdWluZWEgRWN1YXRvcmlhbCwgTGliaWEgeSBCb3Rzd2FuYS4gTWllbnRyYXMgcXVlIGxvcyBkZSBtZW5vciBQQkkgcGVyIGPDoXBpdGEgc29uLCBlbnRyZSBvdHJvczsgTmlnZXJpYSwgU3Vkw6FuLCBNYWRhZ2FzY2FyLCBldGMuIEhheSBtYXlvciBwcm9wb3JjacOzbiBkZSBwYcOtc2VzIGNvbiBQQkkgcGVyIGPDoXBpdGEgYmFqby4NCg0KDQoNCg0KDQoNCg==